#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<list>
#include<map>
#include<array>
#include<assert.h>
#include<algorithm>  
#include<functional>
using namespace std;
 
struct Point
{
	int _x;
	int _y; 
};

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

//列表初始化
//一切都可以使用列表初始化{ }
void Test2_1()
{
	
	int x1 = 1;
	//使用初始化列表时，可添加等号(=)，也可不添加。
	int x2 = { 2 };
	int array1[] = { 1, 2, 3, 4, 5 };
	int array2[5] = { 0 };
	Point p = { 1, 2 };
	//int x2{ 2 };
	//int array1[]{ 1, 2, 3, 4, 5 };
	//int array2[5]{ 0 };
	//Point p{ 1, 2 };
	 
	//创建对象时也可以使用列表初始化方式调用构造函数初始化
	Date d1(2022, 1, 1); // 构造函数
	// C++11支持的列表初始化，这里会调用构造函数初始化

	//可理解成类型转换  先构造一个临时对象，临时对象拷贝构造d2
	//构造+拷贝构造+优化
	Date d2{ 2022, 1, 2 };//编译器优化直接调构造函数
	Date d3 = { 2022, 1, 3 };

	const Date& d4 = { 2022,1,4 };

	// C++11中列表初始化也可以适用于new表达式中
	int* pa = new int[4] { 0 };
	Date* p1 = new Date[3]{ d1,d2,d3 };
	//也是多参数构造类型转换	构造+拷贝构造+优化
	Date* p2 = new Date[3]{ { 2022, 1, 2 },{ 2022, 1, 3 },{ 2022, 1, 4 } };
}

void Test2_2()
{//initializer_list
//支持initializer_list的构造的容器，可以{}初始化
	//vector (initializer_list<value_type> il,
	//const allocator_type& alloc = allocator_type());
	vector<int> v1 = { 1,2,3,4 };
	vector<int> v2 = { 1,2,3,4 };
	//{}内识别的是initializer_list类
	//可以遍历就好实现构造，可以区间，也可以依次插入
	list<int> lt = { 1,2,3,4 };
	initializer_list<int> il1 = { 10,20,35 };
	//initializer_list类支持迭代器，支持遍历
	initializer_list<int>::iterator it = il1.begin();
	while (it != il1.end())
	{
		//...
		++it;
	}

	v1 = { 10,20,30 };//赋值重载的initializer_list版本

	pair<string, string> kv1("sort", "排序");//pair构造
	map<string, string> dict = { kv1,{"insert","插入"}, {"get","获取" } };
									//{}pair多参数构造隐式类型转换
									//{}map的initializer_list构造
	for (auto kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}

	//和上面不同，这是多参数构造类型转换	构造+拷贝构造+优化
	//跟对应构造函数参数个数匹配
	Date d1 = { 2025,3,18 };//参数匹配构造函数，识别成隐式类型转换
							//参数不匹配，识别成initializer_list
							//需要initializer_list版本构造才能初始化
}



//声明
void Test3_1()
{//关键字decltype将变量的类型声明为表达式指定的类型。

	int i = 1;
	double d = 2.2;

	//typeid类型以字符串形式获取到
	cout << typeid(i).name() << endl;
	cout << typeid(d).name() << endl;

	//定义一个和i一样类型的变量
	auto j = i;

	auto ret = i * d;
	//用ret的类型去实例化vector,auto就用不了了
	//decltype可以推到对象的类型
	//这个类型可以用来模板实参，或者再定义对象
	vector<decltype(ret)> v;
	v.push_back(1);
	v.push_back(1.1);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	//定义一个和x一样类型的变量
	decltype(ret) x;


	//#define NULL 0
	//果传给一个重载函数，可能会错误地匹配到
	//接受整数的版本而不是指针版本。
	//而 nullptr 则不会发生这种情况，因为它不能隐式转换为整数类型。
	//可理解成#define nullptr ((void*)0),但nullptr是关键字
	//不是这样实现的
}


//STL新容器
void Test4_1()
{//array
	array<int,10> a1;//静态数组
					 //内存开在栈上
	vector<int> v1(10, 0);//开再堆上，还能初始化

//forward_list	//单链表	节省空间
				//只适合头插头删
}
 

//左值引用和右值引用
void Test5_1()
{
	//左值是一个表示数据的表达式(如变量名或解引用的指针)，
	//我们可以获取它的地址+可以对它赋值，左值可以
	//出现赋值符号的左边，右值不能出现在赋值符号左边。
	// 定义时const修饰符后的左值，不能给他赋值，
	// 但是可以取它的地址。左值引用就是给左值的引用，给左值取别名。
	
	// 以下的p、b、c、*p都是左值
	int* p = new int(0);
	int b = 1;
	const int c = 2;
	// 以下几个是对上面左值的左值引用
	int*& rp = p;
	int& rb = b;
	const int& rc = c;
	int& pvalue = *p;


	//右值也是一个表示数据的表达式，如：字面常量、表达式返回值，
	//函数返回值(这个不能是左值引用返回)等等，
	//右值可以出现在赋值符号的右边，但是不能出现出现在赋值符号的左边，
	//右值不能取地址。右值引用就是对右值的引用，给右值取别名。
	double x = 1.1, y = 2.2;
	// 以下几个都是常见的右值
	10;				//常量
	x + y;			//表达式返回值
	fmin(x, y);		//函数返回值，传值返回生成临时对象，临时对象是右值

	// 以下几个都是对右值的右值引用
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);

	// 这里编译会报错：error C2106: “=”: 左操作数必须为左值
	//10 = 1;
	//x + y = 1;
	//fmin(x, y) = 1;


	int i = 0;
	int j = 1;
	//左值引用不能给右值取别名
	//权限放大
	//int& r1 = 10;
	//但是const左值引用既可引用左值，也可引用右值。
	const int& r1 = 10;
	const int& r2 = i + j;

	int&& rrr1 = 10;
	int&& rrr2 = i + j;

	//右值引用不能给左值取别名
	//int&& rr3 = i;
	//右值引用可以给move(左值)取别名
	int&& rrr3 = move(i);


}


namespace sbt
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			//这句屏蔽方便观察理解
			cout << "string(char* str)构造" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		// s1.swap(s2)
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		// 拷贝构造
		string(const string& s)//左值走左值引用
			:_str(nullptr)		//右值也可以走const左值引用
		{
			cout << "string(const string& s) -- 深拷贝" << endl;
			string tmp(s._str);
			swap(tmp);
		}
		// 赋值重载
		string& operator=(const string& s)
		{
			cout << "string& operator=(string s) -- 深拷贝" << endl;
			//string tmp(s);
			//swap(tmp);
			if (this != &s)
			{
				char* tmp = new char[s._capacity+1];
				strcpy(tmp, s._str);

				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}
		// 移动构造	//减少了调用函数传值返回拷贝构造深拷贝
		string(string&& s)//将亡值	识别到将亡值	
			:_str(nullptr)						
			, _size(0)					
			, _capacity(0)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);//资源转移给this
		}
		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);//资源转移给this,把this原资源带走
			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		const char* c_str() const
		{
			return _str;
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};
	string to_string(int x)
	{
		string ret;
		while (x)
		{
			int val = x % 10;
			x /= 10;
			ret += ('0' + val);
		}
		reverse(ret.begin(), ret.end());
		return ret;//将亡值		//ps右值：纯右值	内置类型的右值
								//		  将亡值	自定义类型右值,编译器自动识别为将亡值
								//表示一个即将被销毁的对象，但仍然具有持久存储的位置。
								//将亡值允许资源从一个对象转移到另一个对象，而不需要进行深拷贝。
	}//这里不能用左值引用返回，ret除了作用域就销毁了
	//移动构造解决了传值返回两次深拷贝问题
}

//左值引用和右值引用应用场景
void Test5_2()
{
	sbt::string s1;

	s1 = sbt::to_string(1234);//深拷贝拷贝构造给临时变量
							//临时变量深拷贝赋值给s1
							// 两次深拷贝，消耗大
	//赋值重载用的是左值引用返回，出了作用域对象还在

	//放开移动构造和移动赋值后，ret作为将亡值，视作右值
	//调用更符合的移动构造和移动赋值
	//始终保存ret的资源，不需要深拷贝和析构



	sbt::string s2("hello");//构造
	sbt::string s3 = s2;	//拷贝构造
	sbt::string s4 = move(s2);//移动构造，s2视为将亡值
							  //在移动构造中把资源转走了
	//左值move返回值视为右值	//谨慎使用，s2资源没了
	//不改变原s2属性

	//STL在c++11以后，基本都增加了移动构造和移动赋值
}

void Test5_3()
{
	list<sbt::string> lt;

	sbt::string s1("hello");
	lt.push_back(s1);//在新节点拷贝构造一份s1

	lt.push_back(move(s1));//支持移动构造
							//少一次深拷贝
	//void push_back(T&& x)
	//{insert(end(),move(x))}x属性还是左值，需要move
	//右值被右值引用以后，右值引用属性是左值
	//编译器强制转的，右值不能修改，但右值被右值引用需要被修改
	//否则无法实现移动构造和移动赋值

	//iterator insert(iterator pos,T&& x)

	//list_node(T&& x)

}




void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
//函数模板：万能引用
//模板中的&&不代表右值引用，而是万能引用，其既能接收左值又能接收右值。
template<typename T>
void PerfectForward(T&& t)//传左值是左值引用，传右值是右值引用
{
	//引用类型的唯一作用就是限制了接收的类型，后续使用中都退化成了左值
	//期望保持实参的属性
	//只有函数模板中万能引用才能这样用
	//完美转发
	Fun(forward<T>(t));

	//上边Test5_3中list也可以用完美转发解决
}
void Test5_4()
{
	PerfectForward(10);//右值
	int a;
	PerfectForward(a);// 左值
	PerfectForward(std::move(a)); // 右值
	const int b = 8;
	PerfectForward(b);// const 左值
	PerfectForward(std::move(b)); // const 右值
}


class Person
{
public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	/*Person(const Person& p)
	* :_name(p._name)
 ,_age(p._age)
 {}*/
 /*Person& operator=(const Person& p)
 {
 if(this != &p)
 {
 _name = p._name;
 _age = p._age;
 }
 return *this;
 }*/
 /*~Person()
 {}*/
private:
	sbt::string _name;
	int _age;
};

//如果你没有自己实现移动构造函数，且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
//意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数，对于内置类
//型成员会执行逐成员按字节拷贝，自定义类型成员，则需要看这个成员是否实现移动构造，
//如果实现了就调用移动构造，没有实现就调用拷贝构造。

//如果你提供了移动构造或者移动赋值，编译器不会自动提供拷贝构造和拷贝赋值。
void Test6_1()
{
	//如果不写，需要有默认的移动构造或者移动赋值
	//才能调用自定义类型的移动构造和移动赋值
	//如果没有默认的移动构造
	//会调用默认的拷贝构造，或者自己写的拷贝构造
	//默认拷贝构造，对自定义类型，调用其拷贝构造，而非移动构造
	Person s1;
	Person s2 = s1;				//默认拷贝构造
	Person s3 = std::move(s1);	//默认移动构造
	Person s4;
	s4 = std::move(s2);			//默认移动赋值
}

//强制生成默认函数的关键字default
//Person(Person&& p) = default;
//Person(const Person& p) = default;

//禁止生成默认函数的关键字delete
//Person(Person&& p) = delete;



//可变参数模板
// Args是一个模板参数包，args是一个函数形参参数包
// 声明一个参数包Args...args，这个参数包中可以包含0到任意个模板参数。
//template <class ...Args>
//void ShowList(Args... args)
//{
//	cout << sizeof...(args) << endl;//参数有几个
//}

void _ShowList()
{
	cout << endl;
}
//编译时的递归推演
//第一个模板参数依次解析获取参数值
template <class T, class ...Args>
void _ShowList(const T& val, Args... args)
{
	cout << val << " ";
	_ShowList(args...);
}

template <class ...Args>
void ShowList(Args... args)
{

	_ShowList(args...);
}

void Test7_1()
{
	ShowList(1);
	ShowList(1, 2);
	ShowList(1, 2, 3);
	ShowList(1, 2.2, 'x', 3.3);//编译器推出T1,T2,T3,T4
}
//template <class... Args>
//void emplace_back(Args&&... args);
//emplace_back 和push_back区别
void Test7_2()
{
	std::list<sbt::string> lt;
	sbt::string s1("1111");		//构造
	lt.push_back(s1);			//拷贝构造
	lt.push_back(move(s1));		//移动构造
	//多输出一个构造是因为拷贝构造调用现代写法

	sbt::string s2("1111");		//构造
	lt.emplace_back(s2);		//拷贝构造
	lt.emplace_back(move(s2));	//移动构造



	//void push_back(const value_type& val);  // 拷贝插入
	//void push_back(value_type && val);       // 移动插入
	cout << endl;
	lt.push_back("xxxx");		//构造+移动构造
	//value_type写死了，就是string
	//xxxx 是const char*隐式类型转换成string,即构造一个string的临时对象
	// 临时对象是一个右值，无法取地址，没有固定的内存地址且仅在表达式的生命周期内有效
	//故调用移动插入版本，移动构造
	lt.emplace_back("xxxx");	//构造
	//没有隐式类型转换，等到构造的时候，直接用
	//const char*构造
}

//多参数时对比
void Test7_3()
{
	std::list<pair<sbt::string, int>> lt;
	lt.push_back(make_pair("1111", 1));		//构造+移动构造
	//make_pair("1111", 1)从const char*隐式类型转换成string临时对象
	//调用移动构造版本

	lt.emplace_back(make_pair("2222", 2));	//构造
	//make_pair("2222", 2) 创建了一个临时的 std::pair<sbt::string, int> 对象
	//emplace_back 函数接收这个已经构造好的临时 pair 对象
	lt.emplace_back("2222", 2);				//构造
	//("2222", 2)没有隐式类型转换，等到构造的时候，直接用
	//const char*构造
	//emplace_back("2222", 2)多参数时，可以分开一个一个传参
	//直接把参数包，直接构造到结点的val上，把参数包传给pair去构造

	//emplace略微高效，自定义类型深拷贝没有很大提升
	//移动构造成本很低
	//反而浅拷贝，在数据量大的情况下，不用一个个拷贝，
	//直接构造，提升大一点

	pair<sbt::string, int> kv("1111", 1);	//构造
	lt.emplace_back(kv);					//拷贝构造
	//kv是一个左值，调用拷贝构造版本
	//多输出一个构造是因为拷贝构造调用现代写法
}




// lambda表达式		需要可调用对象时，不想调用仿函数，可以使用lambda
struct Goods
{
	string _name;  // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price < gr._price;
	}
};
struct ComparePriceGreater
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price > gr._price;
	}
};

void Test8_1()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
   3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), ComparePriceGreater());
}
//lambda表达式语法	lambda是一个函数对象	底层还是仿函数
//[capture-list] (parameters) mutable -> return-type { statement }
//捕捉列表		  参数列表	()函数默认const	返回值类型		函数体
void Test8_2()
{
	//class <lambda_uuid>
	//class `void __cdecl Test8_2(void)'::`2'::<lambda_1>
	auto f1 = [](int x)->int {cout << x << endl; return 0; };
	//这样f1就是一个可调用的函数对象，类似于仿函数			此处有分号
	//可理解成匿名函数对象
	f1(1);
	cout << typeid(f1).name() << endl;

	auto f2 = [](int x)		//返回值类型可以不写根据返回值推
	{
		cout << x << endl;	//f1和f2类型不一样
		return 0;
	};
	f2(2);

	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
   3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool {return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)->bool {return g1._price > g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate < g2._evaluate; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate > g2._evaluate; });
	//sort模板支持传仿函数，lambda,甚至函数指针。可调用对象即可

}

//捕捉列表
//捕捉列表描述了上下文中那些数据可以被lambda使用，以及使用的方式传值还是传引用。
//[var]：表示值传递方式捕捉变量var
//[=]：表示值传递方式捕获所有父作用域中的变量(包括this)
//[&var]：表示引用传递捕捉变量var
//[&]：表示引用传递捕捉所有父作用域中的变量(包括this)
//[this]：表示值传递方式捕捉当前的this指针
//注意：
//a.父作用域指包含lambda函数的语句块
//b.语法上捕捉列表可由多个捕捉项组成，并以逗号分割。
//	比如：[=, &a, &b]：以引用传递的方式捕捉变量a和b，值传递方式捕捉其他所有变量
//	[&，a, this]：值传递方式捕捉变量a和this，引用方式捕捉其他变量
//c.捕捉列表不允许变量重复传递，否则就会导致编译错误。
//d.在块作用域以外的lambda函数捕捉列表必须为空。
//e.在块作用域中的lambda函数仅能捕捉父作用域中局部变量，捕捉任何非此作用域或者
//非局部变量都会导致编译报错。
//f.lambda表达式之间不能相互赋值，即使看起来类型相同

void Test8_3()
{
	int x = 0, y = 1;
	//交换x,y写法一
	cout << x << " " << y << endl;

	auto f1 = [](int& r1, int& r2)
	{
		int tmp = r1;
		r1 = r2;
		r2 = tmp;
	};
	f1(x, y);
	cout << x << " " << y << endl;
	cout << endl;


	//写法二	[var]：表示值传递方式捕捉变量var
	cout << x << " " << y << endl;
	auto f2 = [x, y]()mutable//x,y可理解成，成为lambda类的成员变量
	{				//lambda表达式默认情况下确实会生成一个带有const成员操作符
		int tmp = x;//调用（即operator()为const）的闭包类型对象。
		x = y;		//这意味着在lambda函数体内不能修改捕获的变量
		y = tmp;	//（通过值捕获的变量被视为const）。然而，当你使用mutable关键字时，
	};				//这将允许lambda的operator()不是const，从而允许修改按值捕获的变量。
	f2();//直接使用即可
	cout << x << " " << y << endl;
	cout << endl;
	//没有修改，因为[val]是值传递

	//写法三	[&var]：表示引用传递捕捉变量var
	cout << x << " " << y << endl;
	auto f3 = [&x, &y]()	//可以不用加mutable,可理解成
	{						//针对引用传递的特殊处理
		int tmp = x;
		x = y;		
		y = tmp;	
	};
	f3();
	cout << x << " " << y << endl;
	cout << endl;
	

	//[=]：表示值传递方式捕获所有父作用域中的变量(包括this)
	class AA
	{
	public:
		void func()
		{
			auto f3 = [=]()	//[this]()
			{						
				cout << a1 << endl;
				cout << a2 << endl;
			};
		}
	private:
		int a1 = 1;
		int a2 = 2;
	};
}

//function包装器
// 类模板原型如下
//template <class T> function;     // undefined
//template <class Ret, class... Args>
//class function<Ret(Args...)>;//很特殊的实例化
//模板参数说明：
//Ret : 被调用函数的返回类型
//Args…：被调用函数的形参

//包装器
//包装的可调用对象，函数指针，仿函数，lambda
//function和bind间接实现可调用对象
void swap_func(int& r1, int& r2)
{
	int tmp = r1;
	r1 = r2;
	r2 = tmp;
}
struct Swap
{
	void operator()(int& r1, int& r2)
	{
		int tmp = r1;
		r1 = r2;
		r2 = tmp;
	}
};
void Test9_1()
{
	int x = 0, y = 1;
	cout << x << " " << y << endl;
	cout << endl;

	auto swaplambda = [](int& x,int& y)	
	{						
		int tmp = x;
		x = y;
		y = tmp;
	};

	//可以包装函数指针
	function<void(int&, int&)> f1 = swap_func;

	//可以包装仿函数对象
	function<void(int&, int&)> f2 = Swap();

	//可以包装lambda
	function<void(int&, int&)> f3 = swaplambda;

	//可调用对象放到容器里					//cmd命令
	map<string, function<void(int&, int&)>>cmdOP =
	{ {"函数指针",swap_func},
	{"仿函数",Swap()} ,
	{"lambda",swaplambda} };

	cmdOP["函数指针"](x, y);
	cout << x << " " << y << endl;
	cout << endl;

	cmdOP["仿函数"](x, y);
	cout << x << " " << y << endl;
	cout << endl;


	cmdOP["lambda"](x, y);
	cout << x << " " << y << endl;
	cout << endl;
}


class Plus
{
public:
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return a + b;
	}
};
//包装成员函数
void Test9_2()
{
	

	//普通函数取地址就是函数名	
	//成员函数取地址，比较特殊，需要加类域和&	静态可不加				
	function<int(int, int)>f1 = &Plus::plusi;
	cout << f1(1, 2) << endl;

	//非静态要加this指针
	function<double(Plus*,double, double)>f2 = &Plus::plusd;
	Plus ps;
	cout << f2(&ps,1.1, 2.2) << endl;

	//编译器特殊处理
	function<double(Plus, double, double)>f3 = &Plus::plusd;
	cout << f3(Plus(), 1.1, 2.2) << endl;
}


//bind包装器
// 原型如下：没有返回值
//template <class Fn, class... Args>
///* unspecified */ bind(Fn&& fn, Args&&... args);
//// with return type (2) 
//template <class Ret, class Fn, class... Args>
///* unspecified */ bind(Fn&& fn, Args&&... args);

int Sub(int a, int b)
{
	return a - b;
}

void Test10_1()
{
	function<int(int, int)> f1 = Sub;
	cout << f1(10, 5) << endl;

	//bind调整参数顺序	_1表示第一个参数，_1针对的时实参10
	function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);
	cout << f2(10, 5) << endl;//10传给_1,但_1在第二个形参位置


	//bind调整参数个数，有些参数可以bind时写死，ps即使三个参数，也能绑死中间参数
	function<int(int)> f3 = bind(Sub, 20, placeholders::_1);
	cout << f3(5) << endl;
	//function的类型就变了

	//把function第一个参数bind成Plus()，方便调用
	function<double(double, double)>f4 = bind(&Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
	cout << f4(1.1, 2.2) << endl;
	
}

int main()
{
	//Test2_1();

	//Test2_2();
	//Test5_2();
	//Test5_3();
	//Test5_4();
	//Test6_1();
	//Test7_1();
	//Test7_2();
	//Test7_3();
	//Test8_2();
	//Test8_3();
	//Test9_1();
	//Test9_2();
	Test10_1();
	return 0;
}

